/*
 * N900Parse.cpp
 *
 *  Created on: Aug 19, 2016
 *      Author: ubuntu
 */

#include "N900Parse.h"
#include <stdio.h>
#include <string.h>
#include "../common.h"
#include <stdlib.h>
#include <syslog.h>

static int inline n900_parse_cardata(unsigned char *buf, size_t len, struct n900_msg *msg);
static int inline n900_parse_gpsdata(unsigned char *buf, size_t len, struct n900_msg *msg);
static int inline n900_parse_report(unsigned char *buf, size_t len, struct n900_msg *msg);
static int inline n900_parse_beat(unsigned char *buf, size_t len, struct n900_msg *msg);
static int inline n900_parse_filetrans(unsigned char *buf, size_t len, struct n900_msg *msg);

int n900_parse_package(unsigned char *buf, size_t len, struct n900_msg *msg)
{
	unsigned char *p = buf + N900_TAG_HEAD_LEN;
	int dlen = len - N900_TAG_HEAD_LEN - N900_TAG_TAIL_LEN;
	int n;
	if (dlen < 0) {
		msg->result = false;
		msg->errnum = 1;
		return -1;
	}
	n = 0;
	msg->sequence = p[n] << 8 | p[n+1];
	n += 2;
	msg->obdid = p[n] << 24 | p[n+1] << 16 | p[n+2] << 8 | p[n+3];
	n += 4;
	msg->type = p[n++];
	size_t flen = p[n] << 8 | p[n+1];
	n += 2;
	if (flen + n != dlen) {
		msg->result = false;
		msg->errnum = 1;
		return -1;
	}
	switch (msg->type) {
	case N900_CARDATA:
		n900_parse_cardata(p+n, flen, msg);
		break;
	case N900_GPSDATA:
		n900_parse_gpsdata(p+n, flen, msg);
		break;
	case N900_REPORT:
		n900_parse_report(p+n, flen, msg);
		break;
	case N900_BEATDATA:
		n900_parse_beat(p+n, flen, msg);
		break;
	case N900_FILETRANS:
		n900_parse_filetrans(p+n, flen, msg);
		break;
	}
	return len;
}

int n900_parse_cardata(unsigned char *buf, size_t len, struct n900_msg *msg)
{
	unsigned char *p = buf;
	size_t i = 0;
	if (len < 13)
	{
		msg->result = false;
		msg->errnum = 1;
		debug(LOG_ERR, "n900cardata: the length of data is not enough");
		return -1;
	}

	msg->msg_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 | p[i+3];
	i += 4;
	msg->m_avgSpeed = p[i++];
	msg->m_maxSpeed = p[i++];
	msg->m_minSpeed = p[i++];

	msg->m_fuleConsumptionTotal = (p[i] << 8 | p[i+1]) * 0.001;
	i += 2;
	msg->m_mileageTotal = (p[i] << 8 | p[i+1]) * 0.001;
	i += 2;
	msg->m_sectionDataCount = p[i++];
	if (i + 6 * msg->m_sectionDataCount > len)
	{
		msg->result = false;
		msg->errnum = 1;
		debug(LOG_ERR, "n900cardata: the length of data is not enough");
		return -1;
	}

	msg->m_sec = (struct subSecdata *)calloc(msg->m_sectionDataCount, sizeof(struct subSecdata));
	if (!(msg->m_sec)) {
		i += 6 * msg->m_sectionDataCount;
	} else {
		for (int k = 0; k < msg->m_sectionDataCount; k++) {
			msg->m_sec[k].id = p[i++];
			msg->m_sec[k].stime = p[i++];
			msg->m_sec[k].mileage = (p[i] << 8 | p[i+1]) * 0.001;
			i += 2;
			msg->m_sec[k].fuelConsumption = (p[i] << 8 | p[i+1]) * 0.001;
			i += 2;
		}
	}

	msg->m_driveActionCount = p[i++];
	if (i + 2 * msg->m_driveActionCount > len)
	{
		msg->result = false;
		msg->errnum = 1;
		debug(LOG_ERR, "n900cardata: the length of data is not enough");
		return -1;
	}

	msg->m_drive = (struct driveAct *)calloc(msg->m_driveActionCount, sizeof(struct driveAct));
	if (msg->m_drive) {
		for (int k = 0; k < msg->m_driveActionCount; k++) {
			msg->m_drive[k].id = p[i++];
			msg->m_drive[k].count = p[i++];
			if (i + msg->m_drive[k].count * 4 > len) {
				msg->result = false;
				msg->errnum = 1;
				debug(LOG_ERR, "n900cardata: the length of data is not enough");
				return -1;
			}
			for (int j = 0; j < msg->m_drive[k].count; j++) {
				time_t ts = p[i] << 24 | p[i+1] <<16 | p[i+2] << 8 | p[i+3];
				i += 4;
				msg->m_drive[k].dtime.push_back(ts);
			}
		}
	}
	msg->result = true;
	msg->errnum = 0;

	return 0;
}

int n900_parse_gpsdata(unsigned char *buf, size_t len, struct n900_msg *msg)
{
	unsigned char *p = buf;
	size_t i = 0;

	msg->m_gpscnt = p[i++];
	if ((i + 14 * msg->m_gpscnt) > len) {
		msg->result = false;
		msg->errnum = 1;
		debug(LOG_ERR, "Gps: The length of gps info data is not enough");
		return -1;
	}

	msg->m_gps = (struct gpsInfo *)calloc(msg->m_gpscnt, sizeof(struct gpsInfo));
	if (!(msg->m_gps)) {
		msg->result = true;
		return -1;
	}

	for (int k = 0; k < msg->m_gpscnt; k++) {
		msg->m_gps[k].m_lat = (p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 | p[i+3]) * 0.00001;
		i += 4;
		msg->m_gps[k].m_latDir = p[i++];
		msg->m_gps[k].m_lng = (p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 | p[i+3]) * 0.00001;
		i += 4;
		msg->m_gps[k].m_lngDir = p[i++];
		msg->m_gps[k].m_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 | p[i+3];
		i += 4;
	}
	msg->result = true;

	return 0;
}

int n900_parse_report(unsigned char *buf, size_t len, struct n900_msg *msg)
{
	unsigned char *p = buf;
	size_t i = 0;
	msg->m_type = p[i++];
	switch (msg->m_type) {
	case N900_RP_FAULT:
		{
			msg->msg_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 | p[i+3];
			i += 4;
			msg->m_faultCnt = p[i++];
			if (msg->m_faultCnt == 0)
				break;
			if (len < (i + msg->m_faultCnt * 3)) {
				msg->result = false;
				msg->errnum = 1;
				return -1;
			}
			msg->m_fault = (struct faultCd *)calloc(msg->m_faultCnt, sizeof(struct faultCd));
			if (msg->m_fault) {
				for (int k = 0; k < msg->m_faultCnt; k++) {
					msg->m_fault[k].id = p[i] << 8 | p[i+1];
					i += 2;
					msg->m_fault[k].status = p[i++];
				}
			}
		}
		break;
	case N900_RP_STALLED:
		{
			msg->msg_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 |  p[i+3];
			i += 4;
		}
		break;
	case N900_RP_LOWVOL:
		{
			msg->msg_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 |  p[i+3];
			i += 4;
			msg->m_voltage = p[i] * 0.1;
		}
		break;
	case N900_RP_SHOCK:
		{
			msg->msg_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 |  p[i+3];
			i += 4;
		}
		break;
	case N900_RP_ONPOW:
		{
			msg->msg_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 |  p[i+3];
			i += 4;
			if (i + 4 <= len) {
				msg->m_offtime = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 |  p[i+3];
				i += 4;
			} else {
				msg->m_offtime = 0;
			}
		}
		break;
	case N900_RP_VINCODE:
		{
			msg->msg_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 |  p[i+3];
			i += 4;
			if (i + 17 == len) {
				memcpy(msg->m_vinCode, &p[i], 17);
				msg->m_vinCode[17] = 0;
				msg->m_protype = 0xFF;
				msg->m_marktype = 0;
			} else {
				msg->m_protype = p[i++];
				msg->m_marktype = p[i++];
				memcpy(msg->m_vinCode, &p[i], 17);
				msg->m_vinCode[17] = 0;
			}
		}
		break;
	case N900_RP_IMSICODE:
		{
			msg->msg_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 |  p[i+3];
			i += 4;
			if (i + 20 < len)
			{
				msg->result = false;
				msg->errnum = 1;
				break;
			}
			memcpy(msg->m_ismiCode, &p[i], len-i);
			msg->m_ismiCode[len-i] = 0;
		}
		break;
	case N900_RP_STATUS:
		{
			msg->msg_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 |  p[i+3];
			i += 4;
			msg->m_status = p[i++];
			msg->m_voltage = p[i++] * 0.1;
		}
		break;
	case N900_RP_EXCEPTN:
		{
			msg->msg_time = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 |  p[i+3];
			i += 4;
			msg->m_exptype = p[i++];
		}
		break;
	default:
		msg->result = false;
		msg->errnum = 2;
		return -1;
	}
	msg->result = true;
	return 0;
}

int n900_parse_beat(unsigned char *buf, size_t len, struct n900_msg *msg)
{
	unsigned char *p = buf;
	size_t i = 0;
	msg->m_type = p[i++];
	switch (msg->m_type) {
	case N900_BT_TIME:
		break;
	case N900_BT_CMD:
		{
			if (i + 2 > len)
			{
				msg->result = false;
				msg->errnum = 1;
				debug(LOG_ERR, "命令申请长度不足");
				return -1;
			}
			msg->m_version = p[i] << 8 | p[i+1];
		}
		break;
	case N900_BT_RESPOND:
		{
			msg->m_cmdType = p[i++];
			switch (msg->m_cmdType) {
			case 0x00:
				debug(LOG_DEBUG, "无需任何操作");
				break;
			case 0x01:
				{
					msg->m_faultCnt = p[i++];
					msg->m_fault = (struct faultCd *)calloc(msg->m_faultCnt, sizeof(struct faultCd));
					if (msg->m_fault) {
						for (size_t k = 0; k < msg->m_faultCnt; k++) {
							msg->m_fault[k].id = p[i] << 8 | p[i+1];
							i += 2;
							msg->m_fault[k].status = p[i++];
						}
					} else {
						i += 3 * msg->m_faultCnt;
					}
					if (i + 14 > len) {
						msg->result = false;
						debug(LOG_DEBUG, "体检数据长度不够");
						return -1;
					}
					msg->m_engineSpeed = p[i] << 8 | p[i+1];
					i += 2;
					msg->m_loop_flag = p[i++];
					msg->m_carspeed = p[i++];
					msg->m_AirFuelRatio = p[i++];
					msg->m_airfuelRatio = msg->m_AirFuelRatio * 0.1;
					msg->m_throttleOpen = p[i++];
					msg->m_engineTemp = p[i++];
					msg->m_inletTemp = p[i++];
					msg->m_atomosPress = p[i++];
					msg->m_inletPress = p[i++];
					msg->m_AirFlow = p[i] << 8 | p[i+1];
					i += 2;
					msg->m_airFlow = msg->m_AirFlow * 0.01;
					msg->m_CtlModeVol = p[i++];
					msg->m_ctlModeVol = msg->m_CtlModeVol * 0.1;
					msg->m_ignitionAngle = p[i++];
				}
				break;
			case 0x02:
				msg->m_clearStatus = p[i++];
				break;
			case 0x03:
				msg->m_paramSetup = p[i++];
				break;
			case 0x04:
				msg->m_version = p[i] << 8 | p[i+1];
				break;
			case 0x80:
				msg->m_mile = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 | p[i+3];
				debug(LOG_DEBUG, "车辆行驶里程: %u Km", msg->m_mile);
				break;
			case 0xF1:
				{
					msg->m_logtype = p[i++];
					msg->m_loglen = p[i] << 8 | p[i+1];
					i += 2;
					if (len - i < msg->m_loglen) {
						msg->result = false;
						return -1;
					}
					msg->m_log = (char *)malloc(msg->m_loglen+1);
					if (msg->m_log == NULL)
						break;
					strncpy(msg->m_log, (char *)&p[i], msg->m_loglen);
					msg->m_log[msg->m_loglen] = 0;
				}
				break;
			default:
				debug(LOG_ERR, "错误的消息回应类型: %d", msg->m_cmdType);
				return -1;
			}
		}
		break;
	case N900_BT_AGPS:
		{
			if (i + 13 > len) {
				msg->result = false;
				msg->errnum = 1;
				debug(LOG_ERR, "AGPS 长度不足");
				return -1;
			}
			msg->m_agpsId = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 | p[i+3];
			i += 4;
			msg->m_agpsLat = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 | p[i+3];
			i += 4;
			msg->m_agpsLon = p[i] << 24 | p[i+1] << 16 | p[i+2] << 8 | p[i+3];
			i += 4;
			msg->m_index = p[i++];
		}
		break;
	default:
		msg->result = false;
		msg->errnum = 3;
		return -1;
	}
	msg->result = true;
	return 0;
}

int n900_parse_filetrans(unsigned char *buf, size_t len, struct n900_msg *msg)
{
	if (len < 34)
	{
		debug(LOG_DEBUG, "文件传输: 长度不够");
		msg->result = false;
	}
	memcpy(msg->m_file, buf, 32);
	msg->m_sequence = buf[32] << 8 | buf[33];
	return 0;
}

void n900_msg_free(struct n900_msg *msg)
{
	if (msg == NULL)
		return;
	switch (msg->type) {
	case N900_CARDATA:
		if (msg->m_sec)
			free(msg->m_sec);
		if (msg->m_drive)
			free(msg->m_drive);
		break;
	case N900_GPSDATA:
		if (msg->m_gps)
			free(msg->m_gps);
		break;
	case N900_REPORT:
		if (msg->m_type != N900_RP_FAULT)
			break;
		if (msg->m_fault)
			free(msg->m_fault);
		break;
	case N900_BEATDATA:
		if (msg->m_type == N900_BT_RESPOND) {
			switch (msg->m_cmdType) {
			case 0x01:
				if (msg->m_fault)
					free(msg->m_fault);
			case 0xF1:
				if (msg->m_log)
					free(msg->m_log);
			}
		}
		break;
	}
}
